package com.ouc.oceanBase.service.impl;

import com.ouc.common.constant.VariableName;
import com.ouc.common.entity.NcData;
import com.ouc.common.entity.NcRecord;
import com.ouc.common.ncRead.NcDao;
import com.ouc.common.utils.ArrayUtils;
import com.ouc.common.utils.MathUtils;
import com.ouc.oceanBase.entity.ContourData;
import com.ouc.oceanBase.pojo.NcCubeData;
import com.ouc.oceanBase.service.FeatureService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ucar.ma2.InvalidRangeException;
import ucar.nc2.NetcdfFile;

import java.io.IOException;
import java.util.Map;

import static com.ouc.common.constant.NcConstants.*;

/**
 * @author B504
 * @date 2023/3/13
 * @apiNote
 */
@Service
public class FeatureServiceImpl implements FeatureService {

  @Autowired
  private NcDao ncDao;

  @Override
  public ContourData<NcCubeData> getNcCubeData(String filePath, String variableName, Float[] lon, Float[] lat, Integer positionOf0) throws IOException, InvalidRangeException {
    NetcdfFile ncFile = NetcdfFile.open(filePath);
    ContourData<NcCubeData> contourData = new ContourData<>();
    contourData.setVariableName(variableName);
    NcCubeData ncCubeData = new NcCubeData();
    if (!CURRENTUV.equals(variableName)) {
      NcRecord ncRecord = ncDao.getData3DWithLimit(ncFile, variableName, lon, lat, positionOf0);
      float[][][] data3D = ncRecord.getData3D();
      float[] values_ = ArrayUtils.flat3D(data3D);
      float minValue = MathUtils.min(values_);
      float maxValue = MathUtils.max(values_);
      contourData.setMinValue(minValue);
      contourData.setMaxValue(maxValue);
      ncCubeData.setValue(data3D);
      Map<String, NcData> ncDataWithLimit = ncDao.getNcDataOfLimitFromVariable(ncFile, variableName, lon, lat);
      float[] lonArr = ncDataWithLimit.get(ncDao.getVariable(ncFile, VariableName.LON).getShortName()).getData1D();
      float[] latArr = ncDataWithLimit.get(ncDao.getVariable(ncFile, VariableName.LAT).getShortName()).getData1D();
      float[] levelArr = ncDataWithLimit.get(ncDao.getVariable(ncFile, VariableName.LEVEL).getShortName()).getData1D();
      ncCubeData.setLevels(levelArr.length);
      ncCubeData.setListLat(latArr);
      ncCubeData.setListLon(lonArr);
      ncCubeData.setDepth(levelArr);
      ncCubeData.setVariableName(variableName);
      contourData.setLatLength(latArr.length);
      contourData.setLonLength(lonArr.length);
      contourData.setLonInterval(lonArr[1] - lonArr[0]);
      contourData.setLatInterval(latArr[1] - latArr[0]);
    } else {
      Map<String, NcData> ncDataWithLimitU = ncDao.getNcDataOfLimitFromVariable(ncFile, UU, lon, lat);
      Map<String, NcData> ncDataWithLimitV = ncDao.getNcDataOfLimitFromVariable(ncFile, VV, lon, lat);
      if (ncDataWithLimitU == null || ncDataWithLimitV == null) {
        return new ContourData<>();
      }
      float[] lonArr = ncDataWithLimitU.get(ncDao.getVariable(ncFile, VariableName.LON).getShortName()).getData1D();
      float[] latArr = ncDataWithLimitU.get(ncDao.getVariable(ncFile, VariableName.LAT).getShortName()).getData1D();
      float[] levelArr = ncDataWithLimitU.get(ncDao.getVariable(ncFile, VariableName.LEVEL).getShortName()).getData1D();
      ncCubeData.setLevels(levelArr.length);
      latArr = ArrayUtils.arr1DDilution(latArr, 0);
      ncCubeData.setListLat(latArr);
      lonArr = ArrayUtils.arr1DDilution(lonArr, 0);
      ncCubeData.setListLon(lonArr);
      ncCubeData.setDepth(levelArr);
      ncCubeData.setVariableName("flow");
      NcRecord ncRecordU = ncDao.getData3DWithLimit(ncFile, UU, lon, lat, positionOf0);
      NcRecord ncRecordV = ncDao.getData3DWithLimit(ncFile, VV, lon, lat, positionOf0);
      float[][][] data3DU = ncRecordU.getData3D();
      float[][][] data3DV = ncRecordV.getData3D();
      float[][][] values = new float[data3DU.length][][];
      for (int i = 0; i < values.length; i++) {
        values[i] = ArrayUtils.arr2DDilution(ArrayUtils.getDataFromUV(data3DU[i], data3DV[i]), 0, 0);
      }
      float[] values_ = ArrayUtils.flat3D(values);
      float minValue = MathUtils.min(values_);
      float maxValue = MathUtils.max(values_);
      contourData.setMinValue(minValue);
      contourData.setMaxValue(maxValue);
      ncCubeData.setValue(values);
      contourData.setLatLength(latArr.length);
      contourData.setLonLength(lonArr.length);
      contourData.setLonInterval(lonArr[1] - lonArr[0]);
      contourData.setLatInterval(latArr[1] - latArr[0]);
    }
    contourData.setData(ncCubeData);
    return contourData;
  }

  @Override
  public ContourData<NcCubeData> getNcCubeData(String filePath, String variableName, Float[] lon, Float[] lat) throws IOException, InvalidRangeException {
    return getNcCubeData(filePath, variableName, lon, lat, null);
  }
}
